package org.snail.attendence.service.impl;

import lombok.NonNull;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang3.StringUtils;
import org.snail.attendence.bean.*;
import org.snail.attendence.mapper.AttendanceCheckMapper;
import org.snail.attendence.service.AttendanceCheckService;
import org.snail.common.DataUtils;
import org.snail.common.ExcelUtils;
import org.snail.constant.ErrCodeConstant;
import org.snail.exception.CommonException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Service
@Log4j
public class AttendanceCheckServiceImpl implements AttendanceCheckService {

    @Autowired
    private AttendanceCheckMapper attendanceCheckMapper;

    @Override
    public List countAttCheck(AttCheckCondition attCheckCondition) {
        return null;
    }

    @Override
    public List findCheckHistory() {
        return null;
    }


    //核算考勤业务逻辑
//    1.导入考勤表，生成相关考勤数据。    --- 异常记录已导入
    //2.累积实时考勤，需要用attendenceCount那张表，累积那张表的一些数组进行运算，预算规则详见数据,注意是从最后一次考勤时间+1开始累积
    public AttendanceCheckDO countAttendance(@NonNull AttCheckCondition attCheckCondition) {
        //2.2 根据查找出的员工考勤小时数进行
        Double weekOverHour = 0.0;          //工作日加班天数
        Double weekendOverHour = 0.0;      //周末加班天数
        Double festivalOverHour = 0.0;      //节假日加班天数
        Double offHour = 0.0;        //调休小时数
        Double wxLeaveHour = 0.0;      //可休天数
        Double leaveHour = 0.0;      //可休天数
        //2.1 首先 根据员工id及日期查找出考勤数据
        List<AttendenceCountDO> attendanceListByCondition = attendanceCheckMapper.findAttendanceListByCondition(attCheckCondition);

        for (AttendenceCountDO attCount : attendanceListByCondition) {
            Double dbWeekOverHour = attCount.getWeekdayOverHour();
            Double dbWeekendOverHour = attCount.getWeekendOverHour();
            Double dbFestivalOverHour = attCount.getFestivalOverHour();      //节假日加班天数
            Double dbOffHour = attCount.getOverHour();
            Double dbWxLeaveHour = attCount.getWxLeaveHour();
            Double dbLeaveHour = attCount.getLeaveHour();      //可休天数

            if (null != dbWeekOverHour && dbWeekOverHour != 0.0) {
                weekOverHour = DataUtils.add(weekOverHour, dbWeekOverHour);    //bigDecimal修改
            }
            if (null != dbWeekendOverHour && dbWeekendOverHour != 0.0) {
                weekendOverHour = DataUtils.add(weekendOverHour, dbWeekendOverHour);
            }
            if (null != dbFestivalOverHour && dbFestivalOverHour != 0.0) {
                festivalOverHour = DataUtils.add(festivalOverHour, dbFestivalOverHour);
            }
            if (null != dbOffHour && dbOffHour != 0.0) {
                offHour = DataUtils.add(offHour, dbOffHour);
            }
            if (null != dbWxLeaveHour && dbWxLeaveHour != 0.0) {
                wxLeaveHour = DataUtils.add(wxLeaveHour, dbWxLeaveHour);   //微信上的事假
            }
            if (null != dbLeaveHour && dbLeaveHour != 0.0) {
                leaveHour = DataUtils.add(leaveHour, dbLeaveHour);     //考勤事假
            }
        }

        //test git
        AttendanceCheckDO check = new AttendanceCheckDO();
        check.setWeekOverHour(weekOverHour);
        check.setWeekendOverHour(weekendOverHour);
        check.setVocationOverHour(festivalOverHour);
        check.setApprovalDay(offHour);
        check.setWxLeaveDay(wxLeaveHour);
        check.setLeaveHour(leaveHour);

        return check;
    }

    /**
     * 点击核算功能
     * @param
     */
    public void countAndClearAtt(AttendanceCheckDO attendanceCheckDO) throws CommonException {
        Date endTime = new Date();
        if (null == attendanceCheckDO || null == attendanceCheckDO.getEndCountTime()) {
            log.error("========考勤核算终止日期为空！" + attendanceCheckDO);
            throw new CommonException(ErrCodeConstant.ILLEGAL_PARAM, "核算终止日期为空！", attendanceCheckDO);
        }
        attendanceCheckDO.setIsDel(0);
        //2.将该条实时记录存入数据库中即可
        attendanceCheckMapper.saveAttendanceHistory(attendanceCheckDO);
    }

    /**
     * 删除考勤记录
     * @param id 历史表主键
     */
    public void deleteAttHistory(@NonNull Integer id) {
        attendanceCheckMapper.delAttHistory(id);
    }

    /**
     * 根据员工删除
     */
    public void deleteAttHistoryByEmpId(@NonNull Integer empId) throws CommonException {
        AttCheckCondition attCheckCondition = new AttCheckCondition();
        attCheckCondition.setEmpId(empId);
        List<AttendanceCheckDO> attHistoryList = findAttHistoryList(attCheckCondition);
        if (null == attHistoryList) {
            return;
        }
        for (AttendanceCheckDO attendanceCheckDO : attHistoryList) {
            Integer id = attendanceCheckDO.getId();
            if (null == id || id < 1) {
                log.error("===考勤历史记录的主键出问题啦！参数：" + attendanceCheckDO);
                throw new CommonException(ErrCodeConstant.ILLEGAL_PARAM, "===考勤历史记录的主键出问题啦！参数：" + attendanceCheckDO);
            }
            deleteAttHistory(attendanceCheckDO.getId());
        }
    }

    public List<AttendanceCheckDO> findAttHistoryList(@NonNull AttCheckCondition attCheckCondition) {
        List<AttendanceCheckDO> attHistoryList = attendanceCheckMapper.findAttHistoryList(attCheckCondition);
        return attHistoryList;
    }


    public void test(AttCheckCondition attCheckCondition) {
        countAttendance(attCheckCondition);
    }


//    3.核算功能，点击核算需要清空上次核算至这次核算之间考勤数据
//    3.1将这次数据进行累积，累积之后存入考勤核算历史表
//    3.2 列出所有核算功能

//    ================================================华丽丽的分割线============================================================
    @Override
    public void finalApproval(CommonsMultipartFile file, HttpServletRequest request) {
        Map<AliWorkDTO,Map<String,Double>> finalAttendance = new HashMap<>();

        String pathHome = request.getSession().getServletContext().getRealPath("upload");
        List<AliWorkDTO> aliWorkDTOList =  ExcelUtils.getListFromExcel(file, pathHome, AliWorkDTO.class, 4);
        List<AliWorkDTO> approvalList = getApprovalList(aliWorkDTOList);
        calcOverHour(finalAttendance,approvalList);
    }
    //获取有关联审批的list
    private List<AliWorkDTO> getApprovalList(List<AliWorkDTO> aliWorkDTOs){
        List<AliWorkDTO> approvalList = new ArrayList<>();
        for(int i=0;i<aliWorkDTOs.size();i++){
            AliWorkDTO aliWorkDTO = aliWorkDTOs.get(i);
            String date = aliWorkDTO.getDateStr();
            if(StringUtils.isNotBlank(aliWorkDTO.getApproval())){
                approvalList.add(aliWorkDTO);
            }
        }
        return approvalList;
    }
    //比较是否加班跨天 需要去除
    private  boolean compareDate(String date,String appr){
        Boolean flag = true;
        List<String> list = new ArrayList<String>();
        String regex="\\d\\d-\\d\\d";
        Pattern pattern =Pattern.compile(regex);
        Matcher matcher=pattern.matcher(appr);
        while(matcher.find()){
            list.add(matcher.group());
        }
        flag = date.contains(list.get(0));
        return flag;
    }
    //返回审批单列表 因为一个审批单里可能有两个审批内容
    private  List<String> getApprovalList(String approval){
        String [] approvals = approval.split("小时");
        return Arrays.asList(approvals);
    }
    //返回有效的加班工作时长
    private  Double getEffectiveHour(String date,String appr){
        Double hour = 0.0;
        List<String> list = getApprovalList(appr);
        for(int i=0;i<list.size();i++){
            String item = list.get(i);
            Boolean effec = compareDate(date,item);
            if(effec){
                String[] str = item.split("\\s");
                hour += Double.valueOf(str[str.length-1]);
            }

        }
        return hour;
    }
    //返回有效的调休工作时长 调休没有跨天bug
    private Double getPaidLeaveHour(String appr){
        Double hour = 0.0;
        List<String> list = getApprovalList(appr);
        for(int i=0;i<list.size();i++){
            String item = list.get(i);
            String[] str = item.split("\\s");
            hour += Double.valueOf(str[str.length-1]);

        }
        return hour;
    }
    //计算有效的加班时长
    private void calcOverHour(Map<AliWorkDTO,Map<String,Double>> finalAttendance,List<AliWorkDTO> approvalList){
        for(int i=0;i<approvalList.size();i++) {
            AliWorkDTO aliWorkDTO = approvalList.get(i);
            String date = aliWorkDTO.getDateStr();
            String approval = aliWorkDTO.getApproval();
            if (approval.contains("加班")) {
                Double overHour = getEffectiveHour(date, approval);
                if (finalAttendance.get(aliWorkDTO) != null) {
                    Map<String, Double> aliWorkDTOMap = finalAttendance.get(aliWorkDTO);
                    if(aliWorkDTOMap.get("overHour")!=null){
                        aliWorkDTOMap.put("overHour", aliWorkDTOMap.get("overHour") + overHour);
                        finalAttendance.put(aliWorkDTO, aliWorkDTOMap);
                    }else{
                        aliWorkDTOMap.put("overHour", overHour);
                        finalAttendance.put(aliWorkDTO, aliWorkDTOMap);
                    }

                } else {
                    Map<String, Double> aliWorkDTOMap = new HashMap<>();
                    aliWorkDTOMap.put("overHour", overHour);
                    finalAttendance.put(aliWorkDTO, aliWorkDTOMap);
                }
            }else if(approval.contains("调休")){
                Double overHour = getPaidLeaveHour(approval);
                if (finalAttendance.get(aliWorkDTO) !=null) {
                    Map<String, Double> aliWorkDTOMap = finalAttendance.get(aliWorkDTO);
                    if(aliWorkDTOMap.get("paidLeave")!=null) {
                        aliWorkDTOMap.put("paidLeave", aliWorkDTOMap.get("paidLeave") + overHour);
                        finalAttendance.put(aliWorkDTO, aliWorkDTOMap);
                    }else{
                        aliWorkDTOMap.put("paidLeave", overHour);
                        finalAttendance.put(aliWorkDTO, aliWorkDTOMap);
                    }
                } else {
                    Map<String, Double> aliWorkDTOMap = new HashMap<>();
                    aliWorkDTOMap.put("paidLeave", overHour);
                    finalAttendance.put(aliWorkDTO, aliWorkDTOMap);
                }
            }
        }
    }

}